package com.zhanglijie.improve.aqs.exclusive;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.LockSupport;

import sun.misc.Unsafe;

/**
 * @author zhanglijie
 * @version 1.0
 * @since 1.1.0 2022/9/11 0011 17:43
 */

public class MyAbstractQueuedSynchronizer {
    private volatile Node head;
    private volatile Node tail;
    private static Thread ownerThread;
    private volatile int state;
    private static Unsafe UNSAFE = getUnsafe();
    private static  long stateOffset ;
    private static  long tailOffset;
    private static  long headOffset;
    private static  long waitStateOffset;
    private static  long nextOffset;

    public Node getHead() {
        return head;
    }

    public void setHead(Node node) {
        this.head = node;
        node.thread = null;
        node.pre = null;
    }

    public Node getTail() {
        return tail;
    }

    public void setTail(Node tail) {
        this.tail = tail;
    }

    public static Thread getOwnerThread() {
        return ownerThread;
    }

    public static void setOwnerThread(Thread ownerThread) {
        MyAbstractQueuedSynchronizer.ownerThread = ownerThread;
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public static class Node{
        static Node SHARED = new Node();//共享模式
        static Node EXCLUSIVE = null;//独占模式
        private Node nextWaiter;//共享或者独占
        private volatile Thread thread;
        private volatile Node pre;
        private volatile Node next;
        private volatile int waitState;//节点的等待状态 默认为0 1-取消状态  -1-信号状态
        private static int CANCELLED = 1;//取消状态
        private static int SIGNAL = -1;//前驱节点如果是SIGNAL状态 那么后继节点才可以阻塞 这样子前驱节点执行完才有能力唤醒后继节点
        private static int PROPAGATE = -3;//仅用于共享模式下释放锁时传播信号 一般不用 解决低版本bug才出现这个状态
        private static int CONDITION = -2;//表示当前节点是处于等待队列中
        public Node(){}
        public Node(Thread thread,Node mode){
            this.thread = thread;
            this.nextWaiter = mode;
        }

        public Node(Thread thread,int waitState){
            this.thread = thread;
            this.waitState = waitState;
        }

        public Node preNode(){
            Node p  = pre;
            if(p == null){
              throw new NullPointerException();
            }
            return p;
        }

        public Node nextNode(){
            Node n = next;
            if(n == null){
                throw new NullPointerException();
            }
            return n;
        }

        /**
         * 判断当前节点是共享模式还是独占模式
         * @return
         */
        public boolean isShared() {
            return nextWaiter == SHARED;
        }
    }


    static{
        try {
            stateOffset = UNSAFE.objectFieldOffset(MyAbstractQueuedSynchronizer.class.getDeclaredField("state"));
            tailOffset = UNSAFE.objectFieldOffset(MyAbstractQueuedSynchronizer.class.getDeclaredField("tail"));
            headOffset = UNSAFE.objectFieldOffset(MyAbstractQueuedSynchronizer.class.getDeclaredField("head"));
            waitStateOffset = UNSAFE.objectFieldOffset(Node.class.getDeclaredField("waitState"));
            nextOffset = UNSAFE.objectFieldOffset(Node.class.getDeclaredField("next"));
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    private static Unsafe getUnsafe(){

        try {
            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            Unsafe obj = (Unsafe) theUnsafe.get(null);//静态变量给个null 实例变量给当前实例对象
            return obj ;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }



    //===============================================下面是互斥特征代码=====================================================

    public void acquire(int arg){
       //尝试快速获得锁 如果失败了就需要排队自旋阻塞  失败：1.入队  2.自旋
        if(!tryAcquire(arg) && acquireQueue(addWaiter(Node.EXCLUSIVE),arg)){
            //再次发起中断  可能中断需要特殊代码处理
            Thread.interrupted();//补偿中断
        }
    }

    /**
     * 入队
     */
    public Node addWaiter(Node mode){
        Node node = new Node(Thread.currentThread(), mode);
        Node pred = tail;
        if(pred != null){//其实这个if代码块和下面casEnQueue 子旋入队代码一致 但是这里写是优化 （balking模式运用）
            node.pre = pred;
            if(compareAndSetTail(pred,node)){
                pred.next = node;
                return node;
            }
        }
        //走到这里表明 head|tail没有初始化 或者上面其余线程cas入队失败了下面必须自旋入队直到成功(这里情况：两个thread都判断state==0,但是一个cas成功了另外一个只能去入队）
        casEnQueue(node);
        return node;

    }

    private Node casEnQueue(Node node) {//enq
        while(true){
          Node tempTail = tail;
          if(tempTail == null) {
              //问题：这里为什么不用现成的Node 而是new Node(null) 一个出来作为头节点.这是因为后续唤醒时候判断条件是（该节点pre节点是否是头节点 然后唤醒本节点线程 把head踢出）
              //如果 把实际节点放在头部 那么下次唤醒将被忽略了 就没处理到  所以将头节点放个null假数据占位
              if (compareAndSetHead(new Node())) {
                  tail = head;
              }
          }else{
              //不需要初始化,其余线程自旋入队
              node.pre = tempTail;
              if(compareAndSetTail(tail,node)){
                  tempTail.next = node;
                  return tempTail;//前驱节点返回
              }
          }
        }
    }

    private boolean compareAndSetHead(Node updateNode){
        return UNSAFE.compareAndSwapObject(this,headOffset,null,updateNode);
    }
    private boolean compareAndSetTail(Node expected,Node updateNode){
        return UNSAFE.compareAndSwapObject(this,tailOffset,expected,updateNode);
    }
    protected boolean compareAndSetWaitState(Node node,int expected,int updateNode){
        return UNSAFE.compareAndSwapInt(node,waitStateOffset,expected,updateNode);
    }
    protected boolean compareAndSetState(int expect,int update){
        return UNSAFE.compareAndSwapInt(this,stateOffset, expect,update);
    }
    private boolean compareAndSetNext(Node pre, Node expect, Object update) {
        return UNSAFE.compareAndSwapObject(pre,nextOffset,expect,update);
    }
    /**
     * 自旋+枪锁+阻塞
     */
    public boolean acquireQueue(Node node,int arg){
        boolean failed = true;
        try {
            boolean isInterrupted = false;
            while (true) {
                //尝试快速获取锁(前驱节点是头节点才去tryAcquire
                Node pre = node.preNode();
                if (pre == head && tryAcquire(arg)) {
                    setHead(node);//把自己置为头节点  pre=null  thread=null
                    pre.next = null;//原头节点next为null 上面一行代码和本行代码作用是踢出原节点 将本节点作为头节点
                    failed = false;
                    return isInterrupted;//默认false 如果由于下面中断后下次循环中断位true
                }
                //阻塞
                if (shouldParkAfterFailedAcquire(node.preNode(), node) && parkAndCheckInterrupted()) {
                    //由于中断情况 才会执行 unpark是不会执行的
                    isInterrupted = true;
                }
            }
        }finally {
            //将该节点放入queue发生异常 要取消
            if(failed) {
                //此代码能执行表示改线程活跃  被唤醒了 表明state 被释放了
                cancelAcquire(node);//取消就是将自己clh队列中移除  next跨越该节点 pre没有
            }
        }
    }

    /**
     * 取消获取锁 这个方法可以定义位abstract  让子类去实现
     * 其实这个方法能达到的效果是： pre指针依旧 只能说node。pre会跨过前面的cacel节点
     *  但是本方法的目的是移除本node, pre.next不能完全做到移除node(node.next=node操作除外）
     * @param node
     */
    private void cancelAcquire(Node node) {
        if(node == null ){
            return;
        }
        node.thread = null;
        Node pre = node.pre;
        //将前面连着的一系列无效状态都移除队列
        while(pre.waitState > 0){//>0 表示无效状态
            node.pre = pre = pre.pre;
        }

        //由于本节点failed 所以状态改为cannel状态 然后移除
        Node preNext = pre.next;
        node.waitState = Node.CANCELLED;
        //如果当前节点是tail节点 就将前驱设置位tail节点 移除本节点
        if(node == tail && compareAndSetTail(node,pre)){
            compareAndSetNext(pre,preNext,null);
        }else{//当前节点在中间位置
            int ws;
            //假设当前节点不是head节点的next(pre 非头节点）
            if(pre != head && ((ws = pre.waitState) == Node.SIGNAL || (ws <= 0 && compareAndSetWaitState(pre,ws,Node.SIGNAL))) && pre.thread != null){
                Node next = node.next;
                if(next != null && next.waitState <= 0) {//如果next状态>0那么此次只能 canelNode.pre=有效preNode  有效的PreNode.next=canelNode
                    compareAndSetNext(pre, preNext, next);
                }
            }else{//pre是头节点，直接唤醒后继节点
                unparkSuccessor(node);
            }
            node.next = node;//help gc 其实后面node.next=null当后继节点醒来会讲node踢出
        }
    }

    /**
     * 检查当前线程是否拥有锁
     * @return
     */
    protected boolean isHeldExclusively() {
        throw new UnsupportedOperationException();
    }

    /**
     * 唤醒后继节点
     * @param node
     */
    private void unparkSuccessor(Node node) {
        int waitState = node.waitState;
        if(waitState < 0 ){//取消状态 或者传播状态
            //把该节点回复位初始化状态 因为该节点要出队了
            compareAndSetWaitState(node,waitState,0);
        }
        Node s = node.next;//获得后继节点
        if(s == null || s.waitState >0){
            s = null;
            for(Node t = tail; t != null && t != node;t = t.pre){
                if(t.waitState <= 0){
                    s = t;//s可以获得node后面节点的第一个正常状态的节点
                }
            }
        }
        if(s != null){
            LockSupport.unpark(s.thread);//唤醒node 后继第一个有效节点
        }
    }

    /**
     * 两个流程会唤醒park
     * 1.正常流程 就是preNode执行完业务后 唤醒next
     * 2.本线程被其他线程中断了 比如别的线程拿到本线程的引用 thread  然后thread。interupt();
     * @return
     */
    private boolean parkAndCheckInterrupted() {
        LockSupport.park(this);//被阻塞的线程会卡在这里 唤醒时间（被其他线程unpark 或者interucpt)
        return Thread.interrupted();//返回中断标记 并清除中断标记  park是false  interupt是true  如果是interupt唤醒而不是LockSupport.unlock()唤醒 就会击穿阻塞标记  下次就不能park()
    }

    /**
     * 尝试阻塞 保证我组赛后能够被唤醒  如果我阻塞后 不能被唤醒我就不能阻塞
     * 那么唤醒条件 肯定是该节点的前驱节点执行完业务后释放锁  唤醒本节点 本节点获得锁 再踢除前驱节点（头节点）
     * @return
     */
    private boolean shouldParkAfterFailedAcquire(Node preNode,Node node) {
        int waitState = preNode.waitState;
        //如果前驱节点是sigal状态 可以阻塞
        if(waitState == Node.SIGNAL){
            return true;
        }
        //如果是取消状态 就向前找一个Signal状态的节点作为前驱节点
        if(waitState > 0){
          do{
              node.pre =preNode = preNode.pre;//让当前节点指向上一个前驱节点  问题：咋都移掉取消状态的节点，这些节点初始值不会移除 等没用了被修改为非法才赋值CANNEL状态所以移除遍历到的CANNEL状态
          }while (preNode.waitState > 0);//preNode会不会有null point危险 ==》不会 因为最头上的就是head（哨兵节点）这个节点thread==null waitState=0  unparkSuccessor+acquireQueue方法中体现
              preNode.next = node;
        }else {//判断为0 初始化状态
            compareAndSetWaitState(preNode,waitState,Node.SIGNAL);//如果这次失败了等下次再来将前驱节点状态从默认状态改为singal(因为只有返回true才会进入阻塞 否则一直自旋修改直到成功）
        }
        return false;
    }

    protected boolean tryAcquire(int arg){
    //这里需要让公平锁和非公平锁来重写
        throw new UnsupportedOperationException("必须子类实现");
    }

    /**
     * 检查队列中是否有前驱节点
     * @return
     */
   public boolean hasQueuePred(){
       Node t = tail;
       Node h = head;
       Node s;
       return h != t && ((s=h.next) == null || s.thread != Thread.currentThread());

   }

    /**
     * 只是放一个state
     * @return
     */
    public  boolean release(){
      //1. state-1
        if(tryRelease(1)){
          Node h = head;
          if(h != null && h.waitState != 0){
              unparkSuccessor(h);//唤醒头节点的后继节点
          }
          return true;
        }
        return false;
    }

    /**
     * 一口气释放所有重入的state如果arg==getState()
     * @param arg
     * @return
     */
    public  boolean release(int arg){

        if(tryRelease(arg)){
            Node h = head;
            if(h != null && h.waitState != 0){
                unparkSuccessor(h);//唤醒头节点的后继节点
            }
            return true;
        }
        return false;
    }

    protected boolean tryRelease(int arg)   {
        //这里需要让公平锁和非公平锁来重写
        throw new UnsupportedOperationException("必须子类实现");
    }

    /**
     * 获取队列中等待的节点 这个原生aqs是没有的
     * @return
     */
    public List<Thread> getQueuedThreads(){
        ArrayList<Thread> res = new ArrayList<>();
        for(Node p = tail; p != null ; p = p.pre){
           if(p.thread != null) {
               res.add(p.thread);
           }
       }
        Collections.reverse(res);
        return res;
    }

    /**
     * 可中断的获取锁 其实就是讲中断异常往外抛出去了而已
     * @param arg
     * @throws InterruptedException
     */
    public final void acquireInterruptibly(int arg) throws InterruptedException {
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        if (!tryAcquire(arg)) {
            doAcquireInterruptibly(arg);
        }
    }

    private void doAcquireInterruptibly(int arg) throws InterruptedException {
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.preNode();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
                if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }


    //============================================================================下面是共享特征代码============================================

    /**
     * 共享锁获取
     * @param arg
     */
    public void acquireSharedInterruptibly(int arg) throws InterruptedException {
        if(Thread.interrupted()){
            throw new InterruptedException();
        }
        //如果<0 表明没拿到锁
        if(tryAcquireShared(arg) < 0) {
            doAcquireSharedInterruptibly(arg);
        }
    }

    /**
     * 1.入队   2.自旋阻塞
     * @param arg
     */
    private void doAcquireSharedInterruptibly(int arg) throws InterruptedException {
        Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            boolean isInterrupted = false;
            while (true) {
                //尝试快速获取锁(前驱节点是头节点才去tryAcquire
                Node pre = node.preNode();
                if (pre == head) {
                    int i = tryAcquireShared(arg);
                    if(i >= 0){//抢锁成功
                       //setHead(node);// 为啥不用这个set头节点 因为这个和reentratlock不同 reentrantLock只会唤醒一个线程去抢state,而Semaphore可能会唤醒多个阻塞线程  那么
                        //假设state=5 一口气五个线程head-> t1->t2->t3->t4->t5将被唤醒 由于t1-t5不知道谁会先执行完业务代码做releas操作，所以head最终可能是t1 t2 t3 t4 t5中某一个
                       setHeadAndPropagate(node,i);
                        pre.next = null;//原头节点next为null 上面一行代码和本行代码作用是踢出原节点 将本节点作为头节点
                        failed = false;
                        return ;
                    }
                }
                //阻塞
                if (shouldParkAfterFailedAcquire(node.preNode(), node) && parkAndCheckInterrupted()) {
                    //由于中断情况 才会执行 unpark是不会执行的
                    throw new InterruptedException();
                }
            }
        }finally {
            //将该节点放入queue发生异常 要取消
            if(failed) {
                //此代码能执行表示改线程活跃  被唤醒了 表明state 被释放了
                cancelAcquire(node);//取消就是将自己clh队列中移除  next跨越该节点 pre没有
            }
        }
    }

    /**
     * 更新头节点 并且更具state是否还有 来看看能不能唤醒后继节点
     * @param node
     * @param state
     */
    private void setHeadAndPropagate(Node node, int state) {
        Node h = head;
        setHead(node);
        // 有资源 || 旧的头被踢出后然后gc回收了 || 旧的头propagateStatus || 新的head再次被踢出gc了 || 新的head的状态是propagateStatus
        if(state > 0 ||  h == null || h.waitState < 0 || (h=head) == null || h.waitState <0){// ||后面的执行是尽可能增加多唤醒的概率
            doReleaseShared();//传播唤醒 尽可能达到semaphore的并发要求在一瞬间（如果唤醒的线程没资源了就会stop)
        }

    }

    /**
     * 尝试获取锁 state--操作
     * @param arg
     * @return
     */
    protected int tryAcquireShared(int arg){
        throw new UnsupportedOperationException();
    }


    /**
     * 共享锁获取
     * @param arg
     */
    public void acquireShared(int arg)   {

        //如果<0 表明没拿到锁
        if(tryAcquireShared(arg) < 0) {
          doAcquireShared(arg);
        }
    }

    /**
     * 不响应中断的入队+自旋
     * @param arg
     */
    private void doAcquireShared(int arg) {
        Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            boolean isInterrupted = false;
            while (true) {
                //尝试快速获取锁(前驱节点是头节点才去tryAcquire
                Node pre = node.preNode();
                if (pre == head) {
                    int i = tryAcquireShared(arg);
                    if(i >= 0){
                       // setHead(node);//把自己置为头节点 替换之前头节点
                        setHeadAndPropagate(node,i);
                        pre.next = null;//原头节点next为null 上面一行代码和本行代码作用是踢出原节点 将本节点作为头节点
                        if(isInterrupted){
                            Thread.currentThread().interrupt();//清除中断标记
                        }
                        failed = false;
                        return ;
                    }
                }
                //阻塞
                if (shouldParkAfterFailedAcquire(node.preNode(), node) && parkAndCheckInterrupted()) {
                    //由于中断情况 才会执行 unpark是不会执行的
                    isInterrupted = true;
                }
            }
        }finally {
            //将该节点放入queue发生异常 要取消
            if(failed) {
                //此代码能执行表示改线程活跃  被唤醒了 表明state 被释放了
                cancelAcquire(node);//取消就是将自己clh队列中移除  next跨越该节点 pre没有
            }
        }
    }


    public boolean  releaseShared(int arg){
        //释放锁
        if(tryReleaseShared(arg)){
            //唤醒
            doReleaseShared();

            /**
             * 下面注释的是1.73 version的版本 有问题会存在有state但是节点没被唤醒的情况 有下面代码就没有doReleaseShared()
             * 因为 waitstate有可能是零 但是不能唤醒   比如state没了  thread11 thead12来拿锁只能等待进队列  但是thread1 thread2执行完了相继释放锁 如果
             * thread1 修改了waitstate=0唤醒了thread11 但是thread11没有及时setHead更新waitsate 那么thread2获得的head的waitstate还是老的0导致不能唤醒thread12
             */
            // Node h;
            // if( h=head != null && h.waitState != 0){
            //     unparkSuccessor(h);
            // }

            return true;
        }
        return false;
    }

    /**
     * 共享锁的加锁和释放锁后唤醒新的线程后枪锁流程都会调用这个方法
     *
     * 我尽可能去唤醒节点不管多少个 直到我退出 那些被唤醒的节点在有限资源n下 只能n个线程真正执行 其他被唤醒的没拿到资源的线程还是会再次park
     */
    private void doReleaseShared() {
        for(;;){
            //可能是多个线程一起释放共享锁
            Node h = head;
            if(head != null && head != tail ){//队列中是有节点的
                int waitState = h.waitState;
                if(waitState == Node.SIGNAL) {
                    //还原head节点为默认状态
                    if (!compareAndSetWaitState(h, Node.SIGNAL, 0)) {
                        continue;//cas失败
                    }
                    unparkSuccessor(h);//cas成功，唤醒后继节点
                }else if (waitState == 0 && !compareAndSetWaitState(h,0,Node.PROPAGATE)){
                    continue;
                }
            }
            //退出,退出为什么是判断头节点没有变 而不是放在unparkSuccessor后面直接break.
            //这样 当前线程可以至少唤醒队列中一个节点 也可能多个阻塞节点的线程
            if(h == head){
                //这个条件成立有两个原因 1.退出线程唤醒后继 后继还没拿到head 退出线程就走到这里了  2.唤醒多个线程后没有资源了那么再次循环后这个一直成立
                //如果不成立 那么退出线程还来不及执行这行代码，后面线程已经拿到head，那么退出线程还可以继续尝试唤醒新头节点的后继（帮助传递唤醒）
                break;
            }
        }
    }

    /**
     * 尝试获取锁 state--操作
     * @param arg
     * @return
     */
    protected boolean tryReleaseShared(int arg){
        throw new UnsupportedOperationException();
    }








    //=========================================================下面是等待队列代码==================================================================

    /**
     * 第一个非空节点是写线程（想获取写线程），则当前读线程需要阻塞等待
     * 为了避免无限期的写饥饿  因为读读不阻塞 所以写线程拿的锁的几率就少了
     */
    public boolean apparentlyFirstQueuedIsExclusive() {
        Node h,s;
        return (h=head) != null && (s=h.next) != null
            && !s.isShared() && s.thread != null;
    }

    /**
     * 条件等待队列对象
     */
    public class ConditionObject implements Condition  {

        private Node firstWaiter;
        private Node lastWaiter;
        private static final int REINTERRUPT = 1;//不上中断位
        private static final int THROW_IE = -1;//直接抛出
        static final long spinForTimeoutThreshold = 1000L;


        @Override
        public void await() throws InterruptedException {
            //检查中断
            if(Thread.interrupted()){
                throw new InterruptedException();
            }
            //1、入队完成
            Node node = addConditionWaiter();
            //2、释放锁&&unparkHeadNextNodeThread（这个方法要定义到外部 因为此时是释放lock锁 释放后自己就要阻塞了 否则我阻塞再释放就死锁了）
            int saveState = fullRelease(node);//可能是重入 所以要释放所有当前线程的state
            /**
             * 上面执行完之后，就必须以多线程的方式思考了：
             *  1.fullRelease执行完后  已经释放state了那么别的线程就可以来获得lock锁了，随意此时可能多个线程存在
             *  2.有没有一种情况 会跳过park()
             *    回答：有可能，因为释放锁，那么其他线程获得锁有可能因为执行signal()唤醒刚入condition队列的节点
             *
             *   所以下面两种情况：
             *    1.signal或者intrerrupt抢在whIle循环之前完成，则代码会跳过while循环（因为节点已经被挪到clh中）
             *    2.signal或者interupt还没有执行完 while就可以执行（节点还没到clh上）
             *
             *    signal处理有两个：一个是正常signal 另一个是正常signal时候clh 的tail的节点是cannel状态
             */
            int interuptMode = 0;
            //signal或者interrupt抢在while之前完成 则代码跳过whIle阻塞代码
            while (!isOnSyncQueue(node)){//不在同步队列中才阻塞方式上面问题2
                //3、阻塞
                LockSupport.park();
                //被唤醒了走下面（中断唤醒|siginal唤醒）
                if((interuptMode=checkInterruptWhileWaiting(node)) != 0){//不等于0表示线程是中断唤醒的
                    break;//退出while
                }
                //继续循环阻塞表示是siginal唤醒的 那么下次!isOnSyncQueue(node)判断时候失败 因为singal已经将线程节点移到clh中了
            }
            //往下走是当前节点已经被挪到clh上了(有两种情况一个是signal挪上去的  一个是interrupt挪上去的）
            //唤醒的线程再次抢锁
            if( acquireQueue(node,saveState) && interuptMode != THROW_IE){
                interuptMode = REINTERRUPT;//singal唤醒挪到clh中并在clh队列中抢到锁
            }

            //走到这里表示已经拿到锁了
            if(node.nextWaiter != null){//如果这里是interrupt触发的，那么此时nextwaiter不为空。而signal触发的node.nextWaiter还是存在的
                //清理条件队列的非condition状态的节点
                unlinkCancelledWaiters();//todo node状态好像没被更新为cannel
            }
            //继续检查中断模式
            if(interuptMode != 0){
                reportInterruptAfterWait(interuptMode);
            }

        }

        private void reportInterruptAfterWait(int interruptMode) throws InterruptedException {
            if(interruptMode == THROW_IE){//抢到锁后 由于是中断触发的所以抛出异常
                throw new InterruptedException();
            }else if(interruptMode == REINTERRUPT){//不是完全由中断触发的 是signal触发的或者即使中断触发但是中断逻辑没处理成功，实际是sigal处理的移动节点
                Thread.currentThread().interrupt();//重置中断位，下次如果阻塞了unpark生效
            }
        }

        /**
         * 检查阻塞时后是否被中断唤醒
         * return THROW_IE:中断后然后中断唤醒的线程挪到clh中（自己去主动挪）
         *        REINTERRUPT：中断后 但是还没来的急去挪到clh中 已经被signal线程挪上去了（被signal线程挪）。但是中断实实在在发生了 所以补上中断位
         *        0不是中断触发唤醒的而是signal线程唤醒的
         * @param node
         * @return
         */
        private int checkInterruptWhileWaiting(Node node) {
            return Thread.interrupted()?//检查是否由interupt触发的，如果是返回true并清除中断标记并处理transferAfterCancelledWait  否则就是singal触发的返回0
               (transferAfterCancelledWait(node)?//是否中断逻辑正常处理（将condiong->clh中）  处理成功返回THROW_IE 处理失败（由与singal先执行竞争导致）补上中断位
                   THROW_IE:REINTERRUPT):0;
        }

        /**
         * 条件队列中线程被中断后处理逻辑
         *  cas状态-》入同步队列
         * @param node
         * @return
         */
        private boolean transferAfterCancelledWait(Node node) {
            if(compareAndSetWaitState(node,Node.CONDITION,0)){
                casEnQueue(node);
                return true;
            }
            //走到这里表示执行signal的线程抢先转移成功，也就是sinal线程将状态从condition->0
            while(!isOnSyncQueue(node)){//被signal线程完成入队流程中还没完成入队 所以当前线程等下
                Thread.yield();
            }
            return false;
        }

        /**
         * 加入condition队列
         * @return
         */
        private Node addConditionWaiter() {
            Node t = lastWaiter;
            //入队前需要先清理Condition队列中CANCELLED状态的节点（比如wait(timeout)已经自动醒了的就要置为取消状态））
            if(t != null && t.waitState != Node.CONDITION){
                unlinkCancelledWaiters();
                t = lastWaiter;
            }

            Node node = new Node(Thread.currentThread(),Node.CONDITION);
            if(t == null){//condition队列还未初始化
                firstWaiter = node;
                //todo lastWaiter = node;  这个在下面会执行
            }else{
                t.nextWaiter = node;
            }
            lastWaiter = node;
            return node;
        }

        /**
         * 将condition队列中非congdidion的节点移除(只有await方法的线程需要释放state失败才会将已经在condition队列的节点状态改为取消状态）
         */
        private void unlinkCancelledWaiters() {
            Node t = firstWaiter;
            Node trail = null;//在遍历过程中，最近一次发现状态为condition状态的节点
            while(t != null){
                Node nextWaiter = t.nextWaiter;
                //第一个节点就是取消状态的节点了
                if(t.waitState != Node.CONDITION){
                    t.nextWaiter = null;
                    if(trail == null){
                        firstWaiter = nextWaiter;
                    }else{
                        trail.nextWaiter = nextWaiter;
                    }
                    if(nextWaiter == null){//遍历到队尾了
                        lastWaiter = trail;
                    }
                }else{//最近一次发现的contiton状态的节点
                    trail = t;
                }
                t = nextWaiter;
            }
        }

        /**
         * 对于中断触发 是不会相应将此节点从condition队列移动到clh队列上的
         */
        @Override
        public void awaitUninterruptibly() {
            Node node = addConditionWaiter();
            int needState = fullRelease(node);
            boolean interrupted = false;
            while (!isOnSyncQueue(node)) {
                LockSupport.park(this);
                //下面只是更新中断状态 不做中断进行相应处理 所以退出while循环的只针对singal有效
                if (Thread.interrupted()) {
                    interrupted = true;
                }
            }
            //走到这里表示已经在clh队列中了
            //抢锁成功补上中断标记执行业务代码 然后unlock唤醒后续节点  或者  由中断触发->唤醒clh队列去去抢锁
            if (acquireQueue(node, needState) || interrupted) {
                Thread.currentThread().interrupt();//由于acquiireQueue中会发生中断补上中断继续执行业务代码 || 就是本身中断唤醒的继而中断触发在clh中抢下锁试下失败了还是会继续按照clh规则走
            }
        }

        @Override
        public long awaitNanos(long nanosTimeout) throws InterruptedException {
            if (Thread.interrupted()) {
                throw new InterruptedException();
            }
            Node node = addConditionWaiter();
            int needState = fullRelease(node);
            final long deadline = System.nanoTime() + nanosTimeout;
            int interruptMode = 0;
            while (!isOnSyncQueue(node)) {
                if (nanosTimeout <= 0L) {
                    transferAfterCancelledWait(node);
                    break;
                }
                //最后1000纳秒不阻塞 采用自旋完成（自旋条件位是否被挪到clh中了）
                if (nanosTimeout >= spinForTimeoutThreshold) {
                    LockSupport.parkNanos(this, nanosTimeout);
                }
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) {
                    break;
                }
                //更新剩余还需要阻塞的时间
                nanosTimeout = deadline - System.nanoTime();
            }
            if (acquireQueue(node, needState) && interruptMode != THROW_IE) {
                interruptMode = REINTERRUPT;
            }
            if (node.nextWaiter != null) {
                unlinkCancelledWaiters();
            }
            if (interruptMode != 0) {
                reportInterruptAfterWait(interruptMode);
            }
            return deadline - System.nanoTime();
        }

        @Override
        public boolean await(long time, TimeUnit unit) throws InterruptedException {
            return false;
        }

        @Override
        public boolean awaitUntil(Date deadline) throws InterruptedException {
            return false;
        }

        /**
         * 唤醒条件队列中一个阻塞线程
         */
        @Override
        public void signal() {
            //唤醒操作
            //先看看自己是否有lock了
            if(!isHeldExclusively()){
                throw new IllegalMonitorStateException();
            }
            Node first = firstWaiter;
            if(first != null){
                doSignal(first);           }
        }

        private void doSignal(Node first) {
            do {
                if ((firstWaiter = firstWaiter.nextWaiter) == null) {//队列中只有一个节点
                    lastWaiter = null;
                }
                //下面的condition队列中不止一个节点的情况
                first.nextWaiter = null;//将头节点断开
            }while(!transferForSignal(first) && (first = firstWaiter) != null);//挪动节点（condition队列-》clh同步队列）
        }


        /**
         * 挪动condition队列的节点到同步队列中
         * @param node
         * @return 挪动成功return true 对于取消状态的节点return false 往后递归直到挪成功一个返回true
         */
        private boolean transferForSignal(Node node) {
            //过滤非法的节点（cancel状态）
            if(!compareAndSetWaitState(node,Node.CONDITION,0)){
                return false;
            }
            //往下走表示修改成功可以挪节点了
            Node p = casEnQueue(node);
            int waitState = p.waitState;
            //如果启动到同步队列的前驱节点是无效状态 | 改为有效状态失败 就直接唤醒得了
            if(waitState >0 || !compareAndSetWaitState(p,waitState,Node.SIGNAL)){
                LockSupport.unpark(node.thread);//todo 两条线  退出lock的时候有争议，这个没争议在await中还会去抢锁
            }
            return true;
        }


        /**
         * 唤醒condition队列中所有节点（不是真的唤醒）
         */
        @Override
        public void signalAll() {
            //唤醒操作
            //先看看自己是否有lock了
            if(!isHeldExclusively()){
                throw new IllegalMonitorStateException();
            }
            Node first = firstWaiter;
            if(first != null){
                doSignalAll(first);
            }
        }

        /**
         * 唤醒所有condition队列中的节点（移动节点不是真的唤醒）
         * @param first
         */
        private void doSignalAll(Node first) {
            lastWaiter = firstWaiter=null;//清空
            do {
                Node next = first.nextWaiter;
                first.nextWaiter = null;
                transferForSignal(first);
                first = next;
            }while (first != null);
        }
    }



    /**
     * 判断当前节点是否在同步队列中
     * @param node
     * @return
     */
    private boolean isOnSyncQueue(Node node) {
        //等待状态和前驱没有只有在condition队列中才会出现
        if(node.waitState == Node.CONDITION || node.pre == null){
            return false;
        }
        if(node.next != null){
            return true;//node有next是在同步队列中，而condition的是用nextWaiter表示的
        }
        //走到这里，其实还有一种中间状态node.next == null但是却已经入队成功了 (casEnqueue入同步队列时候 old-tail指针还没改过来的时候old-tail.next = node
        return findNodeFromTail(node);
    }

    private boolean findNodeFromTail(Node node) {//todo为啥查看在队列上不直接用这个方法呢 这涉及balking设计模式
        Node t = tail;
        for(;;){
            if(t == node){
                return true;
            }
            if(t == null){
                return false;
            }
            t = t.pre;
        }
    }



    /**
     * 完全释放锁
     * @param node
     */
    private int fullRelease(Node node) {
        boolean failed =true;
        try {
            int state = getState();
            if (release(state)) {
                failed = false;
                return state;
            } else {
                throw new IllegalMonitorStateException();//释放失败
            }
        }finally {
            if(failed){//release方法发生异常 该节点就要置为canceled状态
                node.waitState = Node.CANCELLED;
            }
        }
    }

}
